
/**
 * @description: 同步数据
 * @param {*} syncDataFn 同步接口
 * @param {*} type 同步数据的类型  1 订单   2 商品
 * @param {*} mode 数据模式  1 全量   2 增量
 * @param {*} delay_increment 增量获取数据时间间隔 默认10000ms
 * @param {*} delay_increment_timer 增量获取数据时间延迟器
 * @param {*} delay_sync 同步数据延迟频率 默认200ms
 * @return {*}
 */
class SyncData{
    constructor(syncDataFn, type, mode, delay_increment = DELAY_INCREMENT, delay_sync = DELAY_SYNC){
        this.syncDataFn = syncDataFn
        this.type = type
        this.mode = mode
        this.sync_times = 0
        this.last_sync_time = ''
        this.is_normal = true
        this.syncDataParams = []
        this.delay_increment = delay_increment
        this.delay_increment_timer = null
        this.delay_sync = delay_sync
        this.sync_timestamp = 0
        this.is_sync_exceed = false
        this.delay_sync_timer = null
        this.sync_data_timestamp = 0
    }

    /**
     * @description: 设置增量获取数据延迟间隔
     * @cb  回调
     * @return {*}
     */    
    setIncrementDelay(delay = this.delay_increment){
        clearTimeout(this.delay_increment_timer)
        return new Promise(resolve => {
            this.delay_increment_timer = setTimeout(() => {
                resolve(true)
            }, delay)
        })
    }

    /**
     * @description: 启动轮巡同步
     * @return {*}
     */    
    launchLoopSyncData(){
        return new Promise((resolve, reject) => {
            clearInterval(this.delay_sync_timer)
            this.delay_sync_timer = setInterval(() => {
                if(!this.is_normal) return clearInterval(this.delay_sync_timer)
                if(this.syncDataParams.length){
                    if(!this.is_sync_exceed){
                        const current_timestamp = Date.now()
                        if(this.sync_data_timestamp && current_timestamp - this.sync_data_timestamp < this.delay_sync){
                            this.sync_data_timestamp = current_timestamp
                            return
                        }else{
                            this.sync_data_timestamp = current_timestamp
                        }
                        const params = this.syncDataParams.shift()
                        this.syncDataFn(params).then(res => {
                            const {code, msg} = res
                            if(code === 0){
                                const {external_order_id} = params
                                this.updateSyncTimesData([external_order_id])
                                this.calcSyncRequestTimes()
                            }else{
                                clearInterval(this.delay_sync_timer)
                                reject(msg || '同步接口报错')
                            }
                        }).catch(err => {
                            clearInterval(this.delay_sync_timer)
                            reject("其他系统异常")
                        })
                    }else{
                        this.calcSyncRequestTimes()
                    }
                }else{
                    clearInterval(this.delay_sync_timer)
                    resolve(true)
                }
            }, this.delay_sync)
        })
    }

    /**
     * @description: 计算接口请求频次
     * @return {*}
     */
    calcSyncRequestTimes(){
        const current_timestamp = Date.now()
        if(this.sync_times){
            if(this.sync_timestamp > current_timestamp){
                if(this.sync_times === FRENQUENCY - 1){
                    this.is_sync_exceed = true
                }else{
                    this.is_sync_exceed = false
                    this.sync_times++
                }
            }else{
                this.sync_timestamp = current_timestamp + 1000 * RANGE
                this.is_sync_exceed = false
                this.sync_times = 0
            }
        }else{
            this.sync_timestamp = current_timestamp + 1000 * RANGE
            this.is_sync_exceed = false
            this.sync_times++
        }
    }

    /**
     * @description: 更新运行状态
     * @param {*} loopStatus  插件运行状态  true 正常运行  false 异常停止
     * @param {*} loopingMsg  插件运行提示文案
     * @return {*}
     */
    updateLoopStatus(loopStatus = true, loopingMsg = ''){
        if(loopStatus){
            globalData.loopingMsg = '运行中'
        }else{
            globalData.loopingMsg = `异常停止（${loopingMsg}）`
            globalData.pluginEndTime = getDateLocaleString()
        }
        globalData.loopStatus = loopStatus
        updateLoopStatusViews()
    }

    /**
     * @description: 停止同步
     * @return {*}
     */    
    stop(){
        this.is_normal = false
    }

    /**
     * @description: 更新同步数据次数
     * @param {*} idList  需要同步的id列表
     * @return {*}
     */ 
    updateSyncTimesData(idList = []){
        const {mode, type} = this
        chrome.storage.local.get('today_timestamp', res => {
            const origin_times = idList.length
            getSyncLength(type, idList).then(statistics => {
                let {today_timestamp} = res
                if(today_timestamp && (new Date().setHours(0,0,0,0) > new Date(Number(today_timestamp)).setHours(0,0,0,0))){
                    today_timestamp = Date.now()
                    chrome.storage.local.set({today_timestamp})
                    if(mode === 1){
                        if(type === 1){
                            statisticsData.total_order_full += statistics
                        }else if(type === 2){
                            statisticsData.total_goods_full += statistics
                        }
                    }else if(mode === 2){
                        if(type === 1){
                            statisticsData.total_order_full += statistics
                            statisticsData.total_order_increment += origin_times
                        }else if(type === 2){
                            statisticsData.total_goods_full += statistics
                            statisticsData.total_goods_increment += origin_times
                        }
                    }
                    statisticsData.today_order_full = 1
                    statisticsData.today_order_increment = 1
                    statisticsData.today_goods_full = 1
                    statisticsData.today_goods_increment = 1
                    chrome.storage.local.set(statisticsData, () => updateSyncTimesViews())
                }else{
                    if(!today_timestamp){
                        today_timestamp = Date.now()
                        chrome.storage.local.set({today_timestamp})
                    }
                    if(mode === 1){
                        if(type === 1){
                            statisticsData.total_order_full += statistics
                            statisticsData.today_order_full += statistics
                        }else if(type === 2){
                            statisticsData.total_goods_full += statistics
                            statisticsData.today_goods_full += statistics
                        }
                    }else if(mode === 2){
                        if(type === 1){
                            statisticsData.total_order_full += statistics
                            statisticsData.total_order_increment += origin_times
                            statisticsData.today_order_full += statistics
                            statisticsData.today_order_increment += origin_times
                        }else if(type === 2){
                            statisticsData.total_goods_full += statistics
                            statisticsData.total_goods_increment += origin_times
                            statisticsData.today_goods_full += statistics
                            statisticsData.today_goods_increment += origin_times
                        }
                    }
                    chrome.storage.local.set(statisticsData, () => updateSyncTimesViews())
                }
            })
        })
    }

    /**
     * @description: 更新同步数据日期时间
     * @return {*}
     */    
    updateSyncDateData(){
        const {type} = this
        if(type === 1){
            recentlySyncDate.recently_sync_date_order = getDateLocaleString()
        }else if(type === 2){
            recentlySyncDate.recently_sync_date_goods = getDateLocaleString()
        }
        chrome.storage.local.set(recentlySyncDate, () => updateSyncDateViews())
    }


    /**
     * @description: 映射同步数据队列
     * @param {*} arr 数据列表
     * @return {*}
     */    
    formatRequestIntoPromise(arr){
        const {app_key, app_secret, retail_shop_id} = pluginInfo
        return arr.map(item => {
            const {extension: data = {}} = item
            const {sign, timestamp} = getReqParam(app_key, app_secret, data, {retail_shop_id})
            const params = {...data, retail_shop_id, sign, timestamp, app_key}
            return params
        })
    }


    /**
     * @description: 映射商品数据
     * @param {*} arr 数据列表
     * @return {*}
     */    
    formatGoodsRequestIntoPromise(arr){
        return new Promise((resolve, reject) => {
            const {app_key, app_secret, retail_shop_id} = pluginInfo
            const extension_list = arr.map(item => item.extension)
            const idList = extension_list.map(item => item[`${this.type === 1 ? 'external_order_id' : 'external_product_id'}`])
            const idType = this.type === 1 ? 'orders' : 'product_list'
            const data = {[idType]: extension_list}
            const {sign, timestamp} = getReqParam(app_key, app_secret, data, {retail_shop_id})
            const params = {...data, retail_shop_id, sign, timestamp, app_key}
            if(!this.is_sync_exceed){
                const current_timestamp = Date.now()
                if(this.sync_data_timestamp && current_timestamp - this.sync_data_timestamp < this.delay_sync){
                    this.sync_data_timestamp = current_timestamp
                    return resolve(false)
                }else{
                    this.sync_data_timestamp = current_timestamp
                }
                this.syncDataFn(params).then(res => {
                    const {code, msg} = res
                    if(code === 0){
                        this.updateSyncTimesData(idList)
                        this.calcSyncRequestTimes()
                        resolve(true)
                    }else{
                        reject(msg || '同步接口报错')
                    }
                }).catch(err => reject("其他系统异常"))
            }else{
                this.calcSyncRequestTimes()
                resolve(false)
            }
        })
    }


    /**
     * @description: 判断应用是否到期
     * @return {*}
     */    
    estimateExpired(){
        return globalData.expire_time_tamp < Date.now()
    }
}



/**
 * @description: 同步 增量 数据
 * @getIncrementDataFn  获取增量数据接口
 * @syncIncrementDataFn  同步增量数据接口
 * @type  数据类型   1 订单   2 商品
 * @return {*}
 */
class SyncIncrementData extends SyncData{
    constructor(getIncrementDataFn, syncIncrementDataFn, type){
        super(syncIncrementDataFn, type, 2)
        this.getIncrementDataFn = getIncrementDataFn
    }
    /**
     * @description: 开启同步增量数据
     * @return {*}
     */    
    launch(){
        if(!this.is_normal) return
        if(this.estimateExpired()){
            this.is_normal = false
            this.updateLoopStatus(false, "应用到期")
            toastMessage('error', "应用到期")
            return false
        }
        const {client_id} = globalData
        return this.getIncrementDataFn({client_id}).then(res => {
            if(res.code === 0 && res.data){
                 const {data, last_sync_time} = res.data
                this.last_sync_time = last_sync_time
                if(data.length){
                    if(this.type === 3){
                        const promiseArr = this.formatRequestIntoPromise(data)
                        this.syncDataParams.push(...promiseArr)
                        this.launchLoopSyncData().then(() => {
                            this.setIncrementDelay().then(() => this.launch())
                            this.updateLoopStatus()
                        }).catch(err => {
                            // this.is_normal = false
                            this.updateLoopStatus(false, err)
                            toastMessage('error', err)
                        })
                    }else{
                        this.formatGoodsRequestIntoPromise(data).then(res => {
                            this.setIncrementDelay().then(() => this.launch())
                            this.updateLoopStatus()
                        }).catch(err => {
                            this.setIncrementDelay().then(() => this.launch())
                            // this.is_normal = false
                            this.updateLoopStatus(false, err)
                            toastMessage('error', err)
                        })
                    }
                }else{
                    this.setIncrementDelay().then(() => this.launch())
                    this.updateLoopStatus()
                }
            }else{
                // this.is_normal = false
                this.setIncrementDelay().then(() => this.launch())
                this.updateLoopStatus(false, res.message || '获取增量数据出错，请退出插件，刷新页面后重试')
                toastMessage('error', res.message || '获取增量数据出错，请退出插件，刷新页面后重试')
            }
        }).catch(err => {
            // this.is_normal = false
            this.setIncrementDelay().then(() => this.launch())
            this.updateLoopStatus(false, "其他系统异常")
            toastMessage('error', "其他系统异常")
        })
    }
}


/**
 * @description: 同步 全量 数据
 * @getHistoricalDataFn  获取历史数据接口
 * @syncHistoricalDataFn  同步历史数据接口
 * @type  数据类型   1 订单   2 商品
 * @return {*}
 */
class SyncHistoricalData extends SyncData{
    constructor(getHistoricalDataFn, syncHistoricalDataFn, type, order_time){
        super(syncHistoricalDataFn, type, 1)
        this.getHistoricalDataFn = getHistoricalDataFn
        this.page = 1
        this.page_size = 20
        this.order_time = order_time
    }
    /**
     * @description: 开启同步历史数据
     * @return {*}
     */    
    launch(){
        const {page, page_size, order_time} = this
        const data = {page, page_size, order_time}
        return this.getHistoricalDataFn(data).then(res => {
            if(res.code === 0 && res.data){
                const {data, last_sync_time, total_count, page, page_size} = res.data
                this.last_sync_time = last_sync_time
                if(data.length){
                    if(this.type === 3){
                        const promiseArr = this.formatRequestIntoPromise(data)
                        this.syncDataParams.push(...promiseArr)
                        this.launchLoopSyncData().then(() => {
                            if(total_count > page * page_size){
                                this.page++
                                this.launch()
                            }else{
                                setBtnStatus(this.type, 1)
                            }
                            this.updateSyncDateData()
                        }).catch(err => {
                            this.updateSyncDateData()
                            setBtnStatus(this.type, 1)
                            toastMessage('error', err)
                        })
                    }else{
                        this.formatGoodsRequestIntoPromise(data).then(res => {
                            if(res){
                                if(total_count > page * page_size){
                                    this.page++
                                    this.setIncrementDelay(this.delay_sync).then(() => this.launch())
                                }else{
                                    setBtnStatus(this.type, 1)
                                }
                            }else{
                                this.setIncrementDelay(this.delay_sync).then(() => this.launch())
                            }
                            this.updateSyncDateData()
                        }).catch(err => {
                            this.updateSyncDateData()
                            setBtnStatus(this.type, 1)
                            toastMessage('error', err)
                        })
                    }
                }else{
                    setBtnStatus(this.type, 1)
                }
            }else{
                setBtnStatus(this.type, 1)
                toastMessage('error', res.message || '获取历史数据出错，请重试')
            }
        }).catch(err => {
            setBtnStatus(this.type, 1)
            toastMessage('error', "其他系统异常")
        })
    }
}